package br.ufmg.dcc.vod.remoteworkers.processor;

import java.util.concurrent.TimeUnit;

import junit.framework.TestCase;

import org.easymock.classextension.EasyMock;

import br.edu.ufcg.lsd.commune.container.servicemanager.ServiceManager;
import br.edu.ufcg.lsd.commune.container.servicemanager.actions.RepeatedAction;
import br.edu.ufcg.lsd.commune.identification.DeploymentID;
import br.edu.ufcg.lsd.commune.identification.ServiceID;
import br.ufmg.dcc.vod.remoteworkers.Command;
import br.ufmg.dcc.vod.remoteworkers.ID;
import br.ufmg.dcc.vod.remoteworkers.scheduler.CommandInterested;

public class ProcessorImplTest extends TestCase {

	private ProcessorImpl pi;
	private ServiceManager sm;

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		this.pi = new ProcessorImpl();
		this.sm = EasyMock.createMock(ServiceManager.class);
		this.pi.init(sm);
		
		EasyMock.reset(sm);
	}

	@Override
	protected void tearDown() throws Exception {
		EasyMock.verify(sm);
	}
	
	@SuppressWarnings("unchecked")
	public void testProcess() {
		CommandInterested interested = EasyMock.createMock(CommandInterested.class);
		Command command = EasyMock.createMock(Command.class);
		
		interested.iAmWorking(EasyMock.gt(Processor.IDLE_TOKEN), EasyMock.eq(pi));
		EasyMock.expectLastCall().once();
		
		ServiceID id = new ServiceID("arthur", "localhost", "earth", "towel");
		DeploymentID did = new DeploymentID(id);
		EasyMock.expect(sm.getStubDeploymentID(interested)).andReturn(did);
		
		EasyMock.expect(sm.registerInterest(ProcessorImpl.OBJECT_NAME, id.toString(), CommandInterested.class)).andReturn(interested);
	
		sm.addActionForRepetition(EasyMock.eq(ProcessorImpl.WORK_ACTION_NAME), (RepeatedAction) EasyMock.anyObject());
		EasyMock.expectLastCall().once();
		
		EasyMock.expect(sm.scheduleActionToRunOnce(EasyMock.eq(ProcessorImpl.WORK_ACTION_NAME), EasyMock.eq(0l), EasyMock.eq(TimeUnit.MICROSECONDS), EasyMock.isA(WorkHandle.class))).andReturn(new FakeFuture());
		
		EasyMock.replay(sm);
		EasyMock.replay(interested);
		
		assertNull(pi.getMaster());
		assertNull(pi.getMasterID());
		assertEquals(Processor.IDLE_TOKEN, pi.getToken());
		pi.process(interested, command);
		assertTrue(Processor.IDLE_TOKEN != pi.getToken());
		assertEquals(interested, pi.getMaster());
		assertEquals(id, pi.getMasterID());

		EasyMock.verify(sm);
		EasyMock.verify(interested);
	}

	@SuppressWarnings("unchecked")
	public void testProcess2() {
		CommandInterested interested = EasyMock.createMock(CommandInterested.class);
		Command command = EasyMock.createMock(Command.class);
		EasyMock.expect(command.getID()).andReturn(new ID("i"));
		
		interested.iAmWorking(EasyMock.gt(Processor.IDLE_TOKEN), EasyMock.eq(pi));
		EasyMock.expectLastCall().once();
		
		ServiceID id = new ServiceID("arthur", "localhost", "earth", "towel");
		DeploymentID did = new DeploymentID(id);
		EasyMock.expect(sm.getStubDeploymentID(interested)).andReturn(did);
		
		EasyMock.expect(sm.registerInterest(ProcessorImpl.OBJECT_NAME, id.toString(), CommandInterested.class)).andReturn(interested);
	
		sm.addActionForRepetition(EasyMock.eq(ProcessorImpl.WORK_ACTION_NAME), (RepeatedAction) EasyMock.anyObject());
		EasyMock.expectLastCall().once();
		
		EasyMock.expect(sm.scheduleActionToRunOnce(EasyMock.eq(ProcessorImpl.WORK_ACTION_NAME), EasyMock.eq(0l), EasyMock.eq(TimeUnit.MICROSECONDS), EasyMock.isA(WorkHandle.class))).andReturn(new FakeFuture());
		
		interested.commandException(EasyMock.eq(new ID("i")), EasyMock.isA(NotIdleException.class));
		
		EasyMock.replay(sm);
		EasyMock.replay(interested);
		EasyMock.replay(command);
		
		assertNull(pi.getMaster());
		assertNull(pi.getMasterID());
		assertEquals(Processor.IDLE_TOKEN, pi.getToken());
		pi.process(interested, command);
		assertTrue(Processor.IDLE_TOKEN != pi.getToken());
		assertEquals(interested, pi.getMaster());
		assertEquals(id, pi.getMasterID());

		pi.process(interested, command);
		
		EasyMock.verify(sm);
		EasyMock.verify(interested);
		EasyMock.verify(command);
	}
	
	public void testInterestedUp() {
		fail("Not yet implemented");
	}

	public void testInterestedDown() {
		fail("Not yet implemented");
	}

	public void testWorkDone() {
		fail("Not yet implemented");
	}

	public void testRelease() {
		fail("Not yet implemented");
	}

}
